/* **********************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* **********************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using System.Collections;
using System.IO.Packaging;
using Microsoft.Office.Interop.PowerPoint;
using OfficeOpenXMLInterop;


namespace Theme_Builder
{
    // TODO: a great deal of cleanup of this file is needed in order to refactor what is where in the context
    //  of ui vs. functionality.  Much of the logic contained in here should probably be moved to the Utility
    //  project eventually.

    // TODO: We are not shielding users from seeing exception errors while working.
    //  This needs to be updated so that we catch errors correctly and handle errors correctly in conjunction
    //  with the ErrorLog part of the Utility project.  Debug builds should still express these errors.

    public partial class FormThemeBuilder : Form
    {
        private Hashtable relBlips;
        private string currentFilePath;
        private string relString;
        private int relId;
        private ApplicationClass pptApp;
        private string testPresentationName;
        private string TempPath;
        bool firstSave;                 // created to ask if overwrite on first save

        private class FillStyleControls
        {
            public FillStyleControls( ComboBox c, EditColor ec, GradientEditor ge, EditImage ei )
            {
                comboFill = c; editColor = ec; gradientEditor = ge; editImage = ei;
            }
            public ComboBox comboFill;
            public EditColor editColor;
            public GradientEditor gradientEditor;
            public EditImage editImage;
        };
        private FillStyleControls[] fillControls = new FillStyleControls[6];

        private class EffectStyleControls
        {
            public EffectStyleControls( EditEffect ee, CheckBox c, EditScene es, Edit3D e3 )
            {
                editEffect = ee; enable3D = c; editScene = es; edit3D = e3;
            }
            public EditEffect editEffect;
            public CheckBox enable3D;
            public EditScene editScene;
            public Edit3D edit3D;
        };
        private EffectStyleControls[] effectControls = new EffectStyleControls[3];

        public FormThemeBuilder()
        {
            // Create the temp path
            TempPath = System.IO.Path.GetTempPath() + @"ThemeTool\";

            InitializeComponent();

            this.firstSave = true;

            fillControls[0] = new FillStyleControls(comboBoxSubtleFill, editColorSubtleFill, gradientEditorSubtleFill, editImageSubtleFill);
            fillControls[1] = new FillStyleControls(comboBoxModerateFill, editColorModerateFill, gradientEditorModerateFill, editImageModerateFill);
            fillControls[2] = new FillStyleControls(comboBoxIntenseFill, editColorIntenseFill, gradientEditorIntenseFill, editImageIntenseFill);
            fillControls[3] = new FillStyleControls(comboBoxBgSubtleFill, editColorBgSubtleFill, gradientEditorBgSubtleFill, editImageBgSubtleFill);
            fillControls[4] = new FillStyleControls(comboBoxBgModerateFill, editColorBgModerateFill, gradientEditorBgModerateFill, editImageBgModerateFill);
            fillControls[5] = new FillStyleControls(comboBoxBgIntenseFill, editColorBgIntenseFill, gradientEditorBgIntenseFill, editImageBgIntenseFill);

            effectControls[0] = new EffectStyleControls(editEffectSubtle, checkBoxEnable3DSubtle, editSceneSubtle, edit3DSubtle);
            effectControls[1] = new EffectStyleControls(editEffectModerate, checkBoxEnable3DModerate, editSceneModerate, edit3DModerate);
            effectControls[2] = new EffectStyleControls(editEffectIntense, checkBoxEnable3DIntense, editSceneIntense, edit3DIntense);

            System.Drawing.Text.InstalledFontCollection ifc = new System.Drawing.Text.InstalledFontCollection();
            FontFamily[] ff = ifc.Families;

            this.SetDefaultUI();

            this.relBlips = new Hashtable();
            this.pptApp = null;
            this.testPresentationName = null;

            // Be nice and clean up our temporary file directory from previous runs
            if(Directory.Exists(TempPath))
                Directory.Delete(TempPath, true);

            Directory.CreateDirectory(TempPath);
        }

        private void toolStripButtonTestInPPT_Click(object sender, EventArgs e)
        {
            // TODO: run some type of sanitization on the embeded .pptx

            // FUTURE: restructure this to be more readable and reliable
            Guid tempThemeGuid = Guid.NewGuid();
            string tempTheme = TempPath + tempThemeGuid.ToString() + ".thmx";

            // Hold the currently opened file temporarily and set it to a temp file
            string currentFileStore = this.currentFilePath;
            this.currentFilePath = tempTheme;

            // If we had a theme, go ahead and copy it over to our current directory
            if (currentFileStore != null && currentFileStore != string.Empty)
            {
                File.Copy(currentFileStore, this.currentFilePath, true);
            }
            else
            {
                // We don't currently have a theme loaded, just work with a temp theme
                this.saveFileDialogThmx.FileName = tempTheme;
                CreateNewTheme();
                this.saveFileDialogThmx.FileName = null;
            }

            // Build the theme & reset the title correctly
            string title = this.Text;
            this.toolStripButtonSaveTheme_Click(this, null);
            this.Text = title;

            // Reset the path back to the original
            this.currentFilePath = currentFileStore;

            // Save out our example file if it hasn't been done already

            string testFilePath = TempPath + "TestFile.pptx";
            if(!File.Exists(testFilePath))
            {
                try
                {
                    Assembly assembly = Assembly.GetExecutingAssembly();
                    Stream resourceStream = assembly.GetManifestResourceStream("Theme_Builder.Resources.SamplePresentation.pptx");
                    FileStream fs = new FileStream(testFilePath, FileMode.Create);

                    const int size = 4096;
                    byte[] bytes = new byte[4096];
                    int numBytes;
                    int numWrote = 0;
                    while ((numBytes = resourceStream.Read(bytes, 0, size)) > 0)
                    {
                        fs.Write(bytes, 0, numBytes);
                        numWrote += numBytes;
                    }

                    fs.Close();
                    resourceStream.Close();
                }
                catch
                {
                    System.Diagnostics.Debug.Assert(false, "Exception thrown while trying to create PPTX file.");
                }
            }


            try
            {
                // Launch PowerPoint
                if (this.pptApp == null)
                    this.pptApp = new ApplicationClass();

                if (this.pptApp.Visible != Microsoft.Office.Core.MsoTriState.msoTrue)
                    this.pptApp.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;

                Presentation testPres = null;

                if (this.pptApp.Presentations.Count == 0)
                {
                    // No presentations are open, go ahead and open ours
                    testPres = this.LaunchPPTTest(testFilePath);

                    if (testPres != null)
                    {
                        this.testPresentationName = testPres.FullName;
                    }
                }
                else
                {
                    // Handle the case where ppt was already open, we may or may not already have our file open
                    //  as well, so go through all the open presentations and look for it
                    bool foundIt = false;

                    foreach (Presentation pres in this.pptApp.Presentations)
                    {
                        if (pres.FullName == this.testPresentationName)
                        {
                            foundIt = true;
                            testPres = pres;
                            continue;
                        }
                    }

                    if (!foundIt)
                    {
                        testPres = this.LaunchPPTTest(testFilePath);

                        if (testPres != null)
                        {
                            this.testPresentationName = testPres.FullName;
                        }
                    }
                }

                if (testPres != null)
                {
                    testPres.ApplyTheme(tempTheme);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Assert(false, "Unable to interop with PowerPoint\r\n\r\n" + ex.ToString());

                // The main reason for this functionality to fail is that the user doesn't have the PIA's installed.
                //  Go ahead and inform them of this and ask if they would like to install them
                DialogResult result =  MessageBox.Show("For some reason we were unable to test the theme.  Please ensure that you have the Primary Interop Assemblies installed if you are trying to use this functionality.\r\n\r\nDo you want to install the Primary Interop Assemblies?",
                    "Unable to test theme.",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question);

                // Launch a browser window to install the PIA's
                if (result == DialogResult.Yes)
                {
                    System.Diagnostics.Process.Start(@"http://www.microsoft.com/downloads/details.aspx?familyid=59daebaa-bed4-4282-a28c-b864d8bfa513&displaylang=en");
                }
            }
        }

        private Presentation LaunchPPTTest(string filename)
        {
            try
            {
                return this.pptApp.Presentations.Open2007(filename, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoTrue, Microsoft.Office.Core.MsoTriState.msoTrue, Microsoft.Office.Core.MsoTriState.msoTrue);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to open the sample presentation.\r\n\r\n" + ex.ToString());
            }

            return null;
        }

        public void FillFontComboBox(ComboBox comboBoxFonts)
        {
            // Enumerate the current set of system fonts,
            // and fill the combo box with the names of the fonts.
            foreach (System.Windows.Media.FontFamily fontFamily in System.Windows.Media.Fonts.SystemFontFamilies)
            {
                // FontFamily.Source contains the font family name.
                comboBoxFonts.Items.Add(fontFamily.Source);
            } 

            comboBoxFonts.SelectedIndex = -1;
        }

        #region Set Default UI
        private void SetDefaultUI()
        {
            this.textBoxThemeName.Clear();

            // Reset the fills
            CT_SolidColorFillProperties props = new CT_SolidColorFillProperties();
            props.schemeClr = new CT_SchemeColor();
            props.schemeClr.val = ST_SchemeColorVal.phClr;

            foreach (FillStyleControls fill in this.fillControls)
            {
                fill.editColor.SolidFill = props;
            }

            this.checkBoxUseSystemColors.Checked = true;

            this.comboBoxPlaceholderSample.SelectedIndex = 0;

            // Clear out the color scheme
            this.labelLight1.BackColor = this.labelDark1.ForeColor = this.panelLight1.BackColor = Color.White;
            this.panelLight2.BackColor = Color.White;
            this.labelDark1.BackColor = this.labelLight1.ForeColor = this.panelDark1.BackColor = Color.Black;
            this.panelDark2.BackColor = Color.White;
            this.panelAccent1.BackColor = Color.White;
            this.panelAccent2.BackColor = Color.White;
            this.panelAccent3.BackColor = Color.White;
            this.panelAccent4.BackColor = Color.White;
            this.panelAccent5.BackColor = Color.White;
            this.panelAccent6.BackColor = Color.White;
            this.panelHyperlink.BackColor = Color.White;
            this.panelFollowedHyperlink.BackColor = Color.White;
            this.labelLight2.ForeColor = labelDark2.ForeColor = Color.Black;
            this.labelLight2Show.ForeColor = Color.White;
            this.labelLight1Show.ForeColor = Color.White;

            // Clear out the 'show' of the color scheme
            this.panelDark1Show.BackColor = Color.Black;
            this.panelDark2Show.BackColor = Color.Black;
            this.panelAccent1Show.BackColor = Color.White;
            this.panelAccent2Show.BackColor = Color.White;
            this.panelAccent3Show.BackColor = Color.White;
            this.panelAccent4Show.BackColor = Color.White;
            this.panelAccent5Show.BackColor = Color.White;
            this.panelAccent6Show.BackColor = Color.White;
            this.labelHyperlinkShow.ForeColor = Color.Black;
            this.labelFollowedHyperlinkShow.ForeColor = Color.Black;

            // Populate the font scheme
            FillFontComboBox(this.comboBoxMajorLatin);
            FillFontComboBox(this.comboBoxMajorEastAsian);
            FillFontComboBox(this.comboBoxMajorComplexScript);
            FillFontComboBox(this.comboBoxMinorComplexScript);
            FillFontComboBox(this.comboBoxMinorEastAsian);
            FillFontComboBox(this.comboBoxMinorLatin);
            this.editFontCollectionMajor.SetDefaultUI();
            this.editFontCollectionMinor.SetDefaultUI();

            this.tabControlMain.SelectedTab = this.tabPageColorsFonts;

            // Go ahead and reload the base style sheet at this point in time to reset everything back
            //  to a basic set of functionality
            this.LoadStyleSheet(Theme_Builder.Utility.MinOssUtil.GetBaseStyleSheet());
        }
        #endregion

        #region Load/Save

        private void toolStripButtonSaveAsTheme_Click(object sender, EventArgs e)
        {
            if (this.saveFileDialogThmx.ShowDialog(this) == DialogResult.OK)
            {
                if (this.currentFilePath == null || this.currentFilePath == string.Empty)
                {
                    // No file chosen
                    return;
                }
                else
                {
                    this.currentFilePath = this.saveFileDialogThmx.FileName;
                    CreateNewTheme();
                }
            }
            else
            {
                // The user chose NOT to save the file (i.e. hit cancel) so we need to bail
                return;
            }

            DoSave();
            this.firstSave = false;

            // Change the title of the form to reflect the filename
            int stPos = this.currentFilePath.LastIndexOf(@"\");
            int len = this.currentFilePath.Length;
            string name = this.currentFilePath.Substring(stPos + 1, len - stPos - 1);
            this.Text = name + " - Theme Builder";
        }

        private void toolStripButtonSaveTheme_Click(object sender, EventArgs e)
        {
            // If we don't have a file open already, we're starting from a new theme
            //  so we should create a dummy file for the code below to correctly populate.
            if (this.currentFilePath == null || this.currentFilePath == string.Empty)
            {
                if (this.saveFileDialogThmx.ShowDialog(this) == DialogResult.OK)
                {
                    CreateNewTheme();
                }
                else
                {
                    // The user chose NOT to save the file (i.e. hit cancel) so we need to bail
                    return;
                }
            }
            else
            {
                if (this.firstSave)
                {
                    if (MessageBox.Show("You are about to overwrite your original file, are you sure you would like to overwrite this file?", 
                        "Overwrite?",
                        MessageBoxButtons.YesNo,
                        MessageBoxIcon.Warning) == DialogResult.No)
                    {
                        if (this.saveFileDialogThmx.ShowDialog(this) == DialogResult.OK)
                        {
                            CreateNewTheme();
                        }
                        else
                        {
                            // The user chose NOT to save the file (i.e. hit cancel) so we need to bail
                            return;
                        }
                    }
                }
            }

            DoSave();
            this.firstSave = false;

            // Change the title of the form to reflect the filename
            int stPos = this.currentFilePath.LastIndexOf(@"\");
            int len = this.currentFilePath.Length;
            string name = this.currentFilePath.Substring(stPos + 1, len - stPos - 1);
            this.Text = name + " - Theme Builder";
        }

        private void CreateNewTheme()
        {
            this.currentFilePath = this.saveFileDialogThmx.FileName;

            string themeString = @"theme\theme\theme1.xml";
            string themeManagerString = @"theme\theme\themeManager.xml";
            Uri themeEmptyUri = PackUriHelper.CreatePartUri(new Uri(themeString, UriKind.Relative));
            Uri themeManagerEmptyUri = PackUriHelper.CreatePartUri(new Uri(themeManagerString, UriKind.Relative));
            Uri relativeThemeUri = PackUriHelper.GetRelativeUri(themeManagerEmptyUri, themeEmptyUri);

            Package emptyPack = Package.Open(this.currentFilePath, FileMode.Create);

            // The empty theme should contain a theme manager part and a theme part
            PackagePart themePart = emptyPack.CreatePart(themeEmptyUri, ThemePartTypes.Theme);
            PackagePart themeManagerPart = emptyPack.CreatePart(themeManagerEmptyUri, ThemePartTypes.ThemeManager);

            // Create the relationships
            emptyPack.CreateRelationship(themeManagerEmptyUri, TargetMode.Internal, Namespaces.OfficeDocument);
            themeManagerPart.CreateRelationship(relativeThemeUri, TargetMode.Internal, Namespaces.Theme);

            emptyPack.Close();
        }

        private void DoSave()
        {
            // Create the theme
            CT_OfficeStyleSheet ossPart = this.CreateStyleSheet();

            // Do some verification work on the input style sheet
            ossPart = Theme_Builder.Utility.MinOssUtil.VerifyComplete(ossPart);

            // Write the theme to the specified package
            Package package = Package.Open(this.currentFilePath);

            string theme = @"theme\theme\theme1.xml";

            Uri themeUri = PackUriHelper.CreatePartUri(new Uri(theme, UriKind.Relative));

            PackagePart OSS = package.GetPart(themeUri);

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(OfficeOpenXMLInterop.CT_OfficeStyleSheet));

            XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces();
            xmlns.Add("a", Namespaces.DrawingMLMain);

            XmlTextWriter writer = new XmlTextWriter(OSS.GetStream(FileMode.Create), Encoding.UTF8);
            xmlSerializer.Serialize(writer, ossPart, xmlns);
            writer.Close();

            // Handle the relationships
            PackageRelationshipCollection rels = OSS.GetRelationships();

            // Delete any relationships we have defined
            ArrayList deleteRels = new ArrayList();
            foreach (PackageRelationship rel in rels)
            {
                Uri relUri = PackUriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);

                package.DeletePart(relUri);
                deleteRels.Add(rel.Id);
            }

            // Delete the actual relationships since we couldn't do it in the loop above  :(
            foreach (string relId in deleteRels)
            {
                OSS.DeleteRelationship(relId);
            }

            // Create any new relationships we may have
            string mediaPart = @"theme\media\image";
            int idx = 1;
            foreach (object key in this.relBlips.Keys)
            {
                string path = (string)this.relBlips[key];

                // Handles if there was no image selected
                if (path == null)
                    continue;

                string uriString = mediaPart + idx.ToString() + ".jpeg";
                idx++;
                Uri imageUri = PackUriHelper.CreatePartUri(new Uri(uriString, UriKind.Relative));

                PackagePart imagePart = package.CreatePart(imageUri, @"image/jpeg");
                Stream imageStream = imagePart.GetStream(FileMode.Create);
                Image img = Image.FromFile(path);
                img.Save(imageStream, System.Drawing.Imaging.ImageFormat.Jpeg);

                Uri relUri = PackUriHelper.GetRelativeUri(themeUri, imagePart.Uri);

                OSS.CreateRelationship(relUri, TargetMode.Internal, Namespaces.BlipRel, key.ToString());
            }

            // Update the thumbnail
            string thumbStringUri = @"docProps\thumbnail.jpeg";
            Uri thumbUri = PackUriHelper.CreatePartUri(new Uri(thumbStringUri, UriKind.Relative));

            PackagePart thumbPart = null;
            if (package.PartExists(thumbUri))
            {
                thumbPart = package.GetPart(thumbUri);
            }
            else
            {
                thumbPart = package.CreatePart(thumbUri, @"image/jpeg");
                package.CreateRelationship(thumbUri, TargetMode.Internal, Namespaces.Thumbnail);
            }

            Stream thumbStream = thumbPart.GetStream(FileMode.Create);

            // Get the thumbnail from our list of resources associated with the project
            //  Currently this is just a thumbnail from PPT that has a giant 'X' on it in order
            //  to make the user want to open the theme back up in PPT and save out to regen the
            //  thumbnail correctly.
            Image thumb = Theme_Builder.Properties.Resources.thumbnail;
            thumb.Save(thumbStream, System.Drawing.Imaging.ImageFormat.Jpeg);

            thumbStream.Close();

            package.Close();
        }

        private void toolStripButtonNewTheme_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = "Theme Builder.exe";
            p.Start();
        }

        private void toolStripButtonOpenTheme_Click(object sender, EventArgs e)
        {
            // Open the last known path if we have one
            if (this.currentFilePath != null && this.currentFilePath != string.Empty)
            {
                this.openFileDialogThmx.InitialDirectory = this.currentFilePath.Remove(this.currentFilePath.LastIndexOf("\\")+1);
            }

            if (this.openFileDialogThmx.ShowDialog(this) == DialogResult.OK)
            {
                this.firstSave = true;

                this.currentFilePath = this.openFileDialogThmx.FileName;

                // Change the title of the form to reflect the filename
                int stPos = this.currentFilePath.LastIndexOf(@"\");
                int len = this.currentFilePath.Length;
                string name = this.currentFilePath.Substring(stPos + 1, len - stPos - 1);
                this.Text = name + " - Theme Builder";

                Package package = Package.Open(this.currentFilePath);

                // Get our interesting parts (the theme and it's relationships)
                string theme = @"theme\theme\theme1.xml";

                Uri themeUri = PackUriHelper.CreatePartUri(new Uri(theme, UriKind.Relative));

                // Snag the OSS, and it's relationships
                PackagePart OSS = package.GetPart(themeUri);
                PackageRelationshipCollection rels = OSS.GetRelationships();

                Stream OssStream = OSS.GetStream();

                OfficeOpenXMLInterop.CT_OfficeStyleSheet styleSheet;

                // Serializer for deserializing the xml contained in the OSS
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(OfficeOpenXMLInterop.CT_OfficeStyleSheet));

                styleSheet = (CT_OfficeStyleSheet)xmlSerializer.Deserialize(OssStream);

                // Grab all of our images if they are used and add them to storage
                this.relBlips.Clear();

                foreach (PackageRelationship rel in rels)
                {
                    if (rel.RelationshipType == Namespaces.BlipRel && !this.relBlips.ContainsKey(rel.Id))
                    {
                        Uri testUri = PackUriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
                        PackagePart relPart = package.GetPart(testUri);

                        Image blip = Image.FromStream(relPart.GetStream());

                        Guid guid = Guid.NewGuid();

                        string tempFile = TempPath + guid.ToString() + ".jpeg";

                        blip.Save(tempFile);

                        this.relBlips.Add(rel.Id, tempFile);
                    }
                }

                OssStream.Close();
                package.Close();

                this.LoadStyleSheet(styleSheet);
            }
        }

        #region Create a Style Sheet

        private OfficeOpenXMLInterop.CT_OfficeStyleSheet CreateStyleSheet()
        {
            this.relBlips.Clear();
            this.relString = "rId";
            this.relId = 1;

            OfficeOpenXMLInterop.CT_OfficeStyleSheet styleSheet = new OfficeOpenXMLInterop.CT_OfficeStyleSheet();

            styleSheet.name = this.textBoxThemeName.Text;

            // Create the base styles element
            styleSheet.themeElements = new OfficeOpenXMLInterop.CT_BaseStyles();

            // Set the color scheme
            styleSheet.themeElements.clrScheme = this.CreateColorScheme();

            // Set the font scheme
            styleSheet.themeElements.fontScheme = this.CreateFontScheme();

            styleSheet.themeElements.fmtScheme = new OfficeOpenXMLInterop.CT_StyleMatrix();
            styleSheet.themeElements.fmtScheme.name = this.textBoxThemeName.Text;

            // Set the themed line styles
            styleSheet.themeElements.fmtScheme.lnStyleLst = this.CreateLineStyles();

            // Set the fill styles
            styleSheet.themeElements.fmtScheme.fillStyleLst = this.CreateFillStyles();

            // Set the background fill styles
            styleSheet.themeElements.fmtScheme.bgFillStyleLst = this.CreateBackgroundFillStyles();

            // Grab the effect scheme
            styleSheet.themeElements.fmtScheme.effectStyleLst = this.CreateEffectStyles();
            
            return styleSheet;
        }

        #region Create Color Scheme
        private OfficeOpenXMLInterop.CT_ColorScheme CreateColorScheme()
        {
            OfficeOpenXMLInterop.CT_ColorScheme colorScheme = new OfficeOpenXMLInterop.CT_ColorScheme();

            colorScheme.name = this.textBoxThemeName.Text;

            // Light 1
            colorScheme.lt1 = new OfficeOpenXMLInterop.CT_Color();
            // If we're set to use system colors
            if (this.checkBoxUseSystemColors.Checked)
            {
                colorScheme.lt1.sysClr = new OfficeOpenXMLInterop.CT_SystemColor();
                colorScheme.lt1.sysClr.val = OfficeOpenXMLInterop.ST_SystemColorVal.window;
                colorScheme.lt1.sysClr.lastClr = Converters.ColorToByteRBG(Color.White);
            }
            else
            {
                colorScheme.lt1.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
                colorScheme.lt1.srgbClr.val = Converters.ColorToByteRBG(this.panelLight1.BackColor);
            }

            // Dark 1
            colorScheme.dk1 = new OfficeOpenXMLInterop.CT_Color();
            // If we're set to use system colors
            if (this.checkBoxUseSystemColors.Checked)
            {
                colorScheme.dk1.sysClr = new OfficeOpenXMLInterop.CT_SystemColor();
                colorScheme.dk1.sysClr.val = OfficeOpenXMLInterop.ST_SystemColorVal.windowText;
                colorScheme.dk1.sysClr.lastClr = Converters.ColorToByteRBG(Color.Black);
            }
            else
            {
                colorScheme.dk1.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
                colorScheme.dk1.srgbClr.val = Converters.ColorToByteRBG(this.panelDark1.BackColor);
            }

            // Light 2
            colorScheme.lt2 = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.lt2.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.lt2.srgbClr.val = Converters.ColorToByteRBG(this.panelLight2.BackColor);

            // Dark 2
            colorScheme.dk2 = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.dk2.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.dk2.srgbClr.val = Converters.ColorToByteRBG(this.panelDark2.BackColor);

            // Accent 1
            colorScheme.accent1 = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.accent1.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.accent1.srgbClr.val = Converters.ColorToByteRBG(this.panelAccent1.BackColor);

            // Accent 2
            colorScheme.accent2 = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.accent2.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.accent2.srgbClr.val = Converters.ColorToByteRBG(this.panelAccent2.BackColor);

            // Accent 3
            colorScheme.accent3 = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.accent3.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.accent3.srgbClr.val = Converters.ColorToByteRBG(this.panelAccent3.BackColor);

            // Accent 4
            colorScheme.accent4 = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.accent4.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.accent4.srgbClr.val = Converters.ColorToByteRBG(this.panelAccent4.BackColor);

            // Accent 5
            colorScheme.accent5 = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.accent5.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.accent5.srgbClr.val = Converters.ColorToByteRBG(this.panelAccent5.BackColor);

            // Accent 6
            colorScheme.accent6 = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.accent6.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.accent6.srgbClr.val = Converters.ColorToByteRBG(this.panelAccent6.BackColor);

            // Hyperlink
            colorScheme.hlink = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.hlink.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.hlink.srgbClr.val = Converters.ColorToByteRBG(this.panelHyperlink.BackColor);

            // Followed Hyperlink
            colorScheme.folHlink = new OfficeOpenXMLInterop.CT_Color();
            colorScheme.folHlink.srgbClr = new OfficeOpenXMLInterop.CT_SRgbColor();
            colorScheme.folHlink.srgbClr.val = Converters.ColorToByteRBG(this.panelFollowedHyperlink.BackColor);

            return colorScheme;
        }
        #endregion

        #region Create Font Scheme
        private OfficeOpenXMLInterop.CT_FontScheme CreateFontScheme()
        {
            OfficeOpenXMLInterop.CT_FontScheme fontScheme = new OfficeOpenXMLInterop.CT_FontScheme();

            fontScheme.name = this.textBoxThemeName.Text;

            // Major font
            fontScheme.majorFont = new OfficeOpenXMLInterop.CT_FontCollection();

            fontScheme.majorFont.latin = new OfficeOpenXMLInterop.CT_TextFont();
            fontScheme.majorFont.latin.typeface = this.comboBoxMajorLatin.Text;

            fontScheme.majorFont.cs = new OfficeOpenXMLInterop.CT_TextFont();
            fontScheme.majorFont.cs.typeface = this.comboBoxMajorComplexScript.Text;

            fontScheme.majorFont.ea = new OfficeOpenXMLInterop.CT_TextFont();
            fontScheme.majorFont.ea.typeface = this.comboBoxMajorEastAsian.Text;

            editFontCollectionMajor.GetFonts(fontScheme.majorFont);

            // Minor Fonts
            fontScheme.minorFont = new OfficeOpenXMLInterop.CT_FontCollection();

            fontScheme.minorFont.latin = new OfficeOpenXMLInterop.CT_TextFont();
            fontScheme.minorFont.latin.typeface = this.comboBoxMinorLatin.Text;

            fontScheme.minorFont.cs = new OfficeOpenXMLInterop.CT_TextFont();
            fontScheme.minorFont.cs.typeface = this.comboBoxMinorComplexScript.Text;

            fontScheme.minorFont.ea = new OfficeOpenXMLInterop.CT_TextFont();
            fontScheme.minorFont.ea.typeface = this.comboBoxMinorEastAsian.Text;

            editFontCollectionMinor.GetFonts(fontScheme.minorFont);

            return fontScheme;
        }
        #endregion

        #region Create Line Styles
        OfficeOpenXMLInterop.CT_LineProperties[] CreateLineStyles()
        {
            OfficeOpenXMLInterop.CT_LineProperties[] lineStyles = new OfficeOpenXMLInterop.CT_LineProperties[3];

            for (int i = 0; i < 3; i++)
                lineStyles[i] = new OfficeOpenXMLInterop.CT_LineProperties();

            lineStyles[0] = editLineStyleSubtle.LineStyle;
            lineStyles[1] = editLineStyleModerate.LineStyle;
            lineStyles[2] = editLineStyleIntense.LineStyle;

            return lineStyles;
        }
        #endregion

        #region Create Fill Style List
        private void CreateFillStyle(ref object item, FillStyleControls controls)
        {
            switch( controls.comboFill.SelectedIndex)
            {
                case 0:
                    item = controls.editColor.SolidFill;
                    break;
                case 1:
                    item = controls.gradientEditor.GradientFill;
                    break;
                case 2:
                    CT_BlipFillProperties blipProps = controls.editImage.ImageFill;

                    string relKey = this.relString + this.relId.ToString();

                    // If we aren't already tracking this image, add it to our list
                    if (!this.relBlips.ContainsValue(blipProps.blip.embed))
                    {
                        this.relBlips.Add(relKey, blipProps.blip.embed);
                        this.relId++;
                    }
                    else
                    {
                        foreach (object key in this.relBlips.Keys)
                        {
                            string path = (string)this.relBlips[key];
                            if (path == blipProps.blip.embed)
                            {
                                relKey = key.ToString();
                                continue;
                            }
                        }
                    }

                    blipProps.blip.embed = relKey;

                    item = blipProps;
                    break;
                case 3: // TODO: Pattern fill
                default:
                    System.Diagnostics.Debug.Assert(false, "Unhandled case for fill type.");
                    break;
            }
        }

        private OfficeOpenXMLInterop.CT_FillStyleList CreateFillStyles()
        {
            OfficeOpenXMLInterop.CT_FillStyleList fillStyleList = new OfficeOpenXMLInterop.CT_FillStyleList();
            fillStyleList.Items = new object[3];

            for (int i = 0; i < 3; i++ )
                CreateFillStyle(ref fillStyleList.Items[i], fillControls[i]);

            return fillStyleList;
        }

        private OfficeOpenXMLInterop.CT_FillStyleList CreateBackgroundFillStyles()
        {
            OfficeOpenXMLInterop.CT_FillStyleList fillStyleList = new OfficeOpenXMLInterop.CT_FillStyleList();
            fillStyleList.Items = new object[3];

            for (int i = 0; i < 3; i++)
                CreateFillStyle(ref fillStyleList.Items[i], fillControls[i+3]); // +3 to use bg controls.

            return fillStyleList;
        }
        #endregion
        
        #region Create Effect Style List
        private void CreateEffectStyle(OfficeOpenXMLInterop.CT_EffectStyleItem item, EffectStyleControls controls)
        {
            System.Diagnostics.Debug.Assert( item != null );
            item.effectLst = controls.editEffect.EffectList;

            // If we have 3D properties, handle them
            if (controls.enable3D.Checked)
            {
                item.sp3d = controls.edit3D.Shape3D;
                item.scene3d = controls.editScene.Scene3D;
            }
        }

        private OfficeOpenXMLInterop.CT_EffectStyleItem[] CreateEffectStyles()
        {
            CT_EffectStyleItem[] effectList = new CT_EffectStyleItem[3];
            for (int i = 0; i < 3; i++)
            {
                effectList[i] = new CT_EffectStyleItem();
                CreateEffectStyle(effectList[i], effectControls[i]);
            }
            return effectList;
        }

        #endregion

        #endregion

        #region Load a Style Sheet
        private void LoadStyleSheet(OfficeOpenXMLInterop.CT_OfficeStyleSheet styleSheet)
        {
            if(styleSheet == null || styleSheet.themeElements == null)
                return;

            this.textBoxThemeName.Text = styleSheet.name;

            // Load the color scheme
            if (styleSheet.themeElements.clrScheme != null)
            {
                this.LoadColorScheme(styleSheet.themeElements.clrScheme);
            }

            // Load the font scheme
            if (styleSheet.themeElements.fontScheme != null)
            {
                this.LoadFontScheme(styleSheet.themeElements.fontScheme);
            }

            // Load the line styles
            if (styleSheet.themeElements.fmtScheme.lnStyleLst != null)
            {
                this.LoadLineStyles(styleSheet.themeElements.fmtScheme.lnStyleLst);
            }

            // Load the fill styles
            if (styleSheet.themeElements.fmtScheme.fillStyleLst != null)
            {
                this.LoadFillStyles(styleSheet.themeElements.fmtScheme.fillStyleLst);
            }

            // Load the background fill styles
            if (styleSheet.themeElements.fmtScheme.bgFillStyleLst != null)
            {
                this.LoadBackgroundFillStyles(styleSheet.themeElements.fmtScheme.bgFillStyleLst);
            }

            // Load the effect styles
            if (styleSheet.themeElements.fmtScheme.effectStyleLst != null)
            {
                this.LoadEffectStyles(styleSheet.themeElements.fmtScheme.effectStyleLst);
            }

            this.InformPlaceholderColorChanged();
        }

        #region Load Color Scheme
        private void LoadColorScheme(OfficeOpenXMLInterop.CT_ColorScheme colorScheme)
        {
            // Light 1
            if (colorScheme.lt1 != null)
            {
                if (colorScheme.lt1.srgbClr != null)
                {
                    this.checkBoxUseSystemColors.Checked = false;

                    if (colorScheme.lt1.srgbClr.val != null)
                    {
                        SetLight1Color( Converters.ByteRGBToColor(colorScheme.lt1.srgbClr.val) );
                    }
                }
                else if (colorScheme.lt1.sysClr != null)
                {
                    this.checkBoxUseSystemColors.Checked = true;

                    SetLight1Color(Converters.ST_SystemColorValToColor(colorScheme.lt1.sysClr.val));
                }
            }

            // Dark1 1
            if (colorScheme.dk1 != null)
            {
                if (colorScheme.dk1.srgbClr != null)
                {
                    this.checkBoxUseSystemColors.Checked = false;

                    if (colorScheme.dk1.srgbClr.val != null)
                    {
                        SetDark1Color(Converters.ByteRGBToColor(colorScheme.dk1.srgbClr.val));
                    }
                }
                else if (colorScheme.dk1.sysClr != null)
                {
                    this.checkBoxUseSystemColors.Checked = true;

                    SetDark1Color(Converters.ST_SystemColorValToColor(colorScheme.dk1.sysClr.val));
                }
            }

            // Light 2
            if (colorScheme.lt2 != null)
            {
                if (colorScheme.lt2.srgbClr != null)
                {
                    if (colorScheme.lt2.srgbClr.val != null)
                    {
                        SetLight2Color(Converters.ByteRGBToColor(colorScheme.lt2.srgbClr.val));
                    }
                }
            }

            // Dark 2
            if (colorScheme.dk2 != null)
            {
                if (colorScheme.dk2.srgbClr != null)
                {
                    if (colorScheme.dk2.srgbClr.val != null)
                    {
                        SetDark2Color(Converters.ByteRGBToColor(colorScheme.dk2.srgbClr.val));
                    }
                }
            }

            // Accent 1
            if (colorScheme.accent1 != null)
            {
                if (colorScheme.accent1.srgbClr != null)
                {
                    if (colorScheme.accent1.srgbClr.val != null)
                    {
                        this.panelAccent1Show.BackColor = this.panelAccent1.BackColor = Converters.ByteRGBToColor(colorScheme.accent1.srgbClr.val);
                    }
                }
            }

            // Accent 2
            if (colorScheme.accent2 != null)
            {
                if (colorScheme.accent2.srgbClr != null)
                {
                    if (colorScheme.accent2.srgbClr.val != null)
                    {
                        this.panelAccent2Show.BackColor = this.panelAccent2.BackColor = Converters.ByteRGBToColor(colorScheme.accent2.srgbClr.val);
                    }
                }
            }

            // Accent 3
            if (colorScheme.accent3 != null)
            {
                if (colorScheme.accent3.srgbClr != null)
                {
                    if (colorScheme.accent3.srgbClr.val != null)
                    {
                        this.panelAccent3Show.BackColor = this.panelAccent3.BackColor = Converters.ByteRGBToColor(colorScheme.accent3.srgbClr.val);
                    }
                }
            }

            // Accent 4
            if (colorScheme.accent4 != null)
            {
                if (colorScheme.accent4.srgbClr != null)
                {
                    if (colorScheme.accent4.srgbClr.val != null)
                    {
                        this.panelAccent4Show.BackColor = this.panelAccent4.BackColor = Converters.ByteRGBToColor(colorScheme.accent4.srgbClr.val);
                    }
                }
            }

            // Accent 5
            if (colorScheme.accent5 != null)
            {
                if (colorScheme.accent5.srgbClr != null)
                {
                    if (colorScheme.accent5.srgbClr.val != null)
                    {
                        this.panelAccent5Show.BackColor = this.panelAccent5.BackColor = Converters.ByteRGBToColor(colorScheme.accent5.srgbClr.val);
                    }
                }
            }

            // Accent 6
            if (colorScheme.accent6 != null)
            {
                if (colorScheme.accent6.srgbClr != null)
                {
                    if (colorScheme.accent6.srgbClr.val != null)
                    {
                        this.panelAccent6Show.BackColor = this.panelAccent6.BackColor = Converters.ByteRGBToColor(colorScheme.accent6.srgbClr.val);
                    }
                }
            }

            // Hyperlink
            if (colorScheme.hlink != null)
            {
                if (colorScheme.hlink.srgbClr != null)
                {
                    if (colorScheme.hlink.srgbClr.val != null)
                    {
                        this.labelHyperlinkShow.ForeColor = this.panelHyperlink.BackColor = Converters.ByteRGBToColor(colorScheme.hlink.srgbClr.val);
                    }
                }
            }

            // Followed Hyperlinke
            if (colorScheme.folHlink != null)
            {
                if (colorScheme.folHlink.srgbClr != null)
                {
                    if (colorScheme.folHlink.srgbClr.val != null)
                    {
                        this.labelFollowedHyperlinkShow.ForeColor = this.panelFollowedHyperlink.BackColor = Converters.ByteRGBToColor(colorScheme.folHlink.srgbClr.val);
                    }
                }
            }
        }
        #endregion

        #region Load Font Scheme
        private void LoadFontScheme(OfficeOpenXMLInterop.CT_FontScheme fontScheme)
        {
            if (fontScheme == null)
                return;

            // Major Font
            if (fontScheme.majorFont != null)
            {
                this.comboBoxMajorLatin.Text = fontScheme.majorFont.latin.typeface;
                this.comboBoxMajorComplexScript.Text = fontScheme.majorFont.cs.typeface;
                this.comboBoxMajorEastAsian.Text = fontScheme.majorFont.ea.typeface;
                editFontCollectionMajor.SetFonts(fontScheme.majorFont);
            }

            // Minor Font
            if (fontScheme.minorFont != null)
            {
                this.comboBoxMinorLatin.Text = fontScheme.minorFont.latin.typeface;
                this.comboBoxMinorComplexScript.Text = fontScheme.minorFont.cs.typeface;
                this.comboBoxMinorEastAsian.Text = fontScheme.minorFont.ea.typeface;
                editFontCollectionMinor.SetFonts(fontScheme.minorFont);
            }
        }
        #endregion

        #region Load Line Styles
        private void LoadLineStyles(OfficeOpenXMLInterop.CT_LineProperties[] lineStyles)
        {
            if (lineStyles.Length != 3)
            {
                System.Diagnostics.Debug.Assert(false, "We don't have 3 line styles");
                return;
            }

            editLineStyleSubtle.LineStyle = lineStyles[0];
            editLineStyleModerate.LineStyle = lineStyles[1];
            editLineStyleIntense.LineStyle = lineStyles[2];
        }
        #endregion

        #region Load Fill Styles

        private void HandleUnknownFillStyle(object unknownFill, FillStyleControls controls)
        {
            if (unknownFill == null)
                return;

            if (unknownFill.GetType() == typeof(OfficeOpenXMLInterop.CT_SolidColorFillProperties))
            {
                // Solid Fill
                OfficeOpenXMLInterop.CT_SolidColorFillProperties solidFill = (OfficeOpenXMLInterop.CT_SolidColorFillProperties)unknownFill;
                controls.editColor.SolidFill = solidFill;
                controls.comboFill.SelectedIndex = 0;
            }
            else if (unknownFill.GetType() == typeof(OfficeOpenXMLInterop.CT_GradientFillProperties))
            {
                // Gradient Fill
                OfficeOpenXMLInterop.CT_GradientFillProperties gradFill = (OfficeOpenXMLInterop.CT_GradientFillProperties)unknownFill;
                controls.gradientEditor.GradientFill = gradFill;
                controls.comboFill.SelectedIndex = 1;
            }
            else if (unknownFill.GetType() == typeof(OfficeOpenXMLInterop.CT_BlipFillProperties))
            {
                // Image Fill
                OfficeOpenXMLInterop.CT_BlipFillProperties imageFill = (OfficeOpenXMLInterop.CT_BlipFillProperties)unknownFill;

                if (imageFill.blip != null && imageFill.blip.embed != null)
                {
                    if (this.relBlips.ContainsKey(imageFill.blip.embed))
                        imageFill.blip.embed = (string)this.relBlips[imageFill.blip.embed];
                }

                controls.editImage.ImageFill = imageFill;
                controls.comboFill.SelectedIndex = 2;
            }
            else if (unknownFill.GetType() == typeof(OfficeOpenXMLInterop.CT_PatternFillProperties))
            {
                // TODO: pattern fill implementation
            }
        }

        private void LoadFillStyles(OfficeOpenXMLInterop.CT_FillStyleList fillStyles)
        {
            if (fillStyles.Items == null || fillStyles.Items.Length < 3)
                return;

            for (int i = 0; i < 3; i++)
                HandleUnknownFillStyle(fillStyles.Items[i], fillControls[i]);
        }

        private void LoadBackgroundFillStyles(OfficeOpenXMLInterop.CT_FillStyleList fillStyles)
        {
            if (fillStyles == null || fillStyles.Items == null || fillStyles.Items.Length < 3)
                return;

            for (int i = 0; i < 3; i++)
                HandleUnknownFillStyle(fillStyles.Items[i], fillControls[i+3]); // +3 because bg controls are indices 3-5
        }

        #endregion

        #region Load Effect Styles
        private void LoadEffectStyle(OfficeOpenXMLInterop.CT_EffectStyleItem item, EffectStyleControls controls)
        {
            if (item == null)
                return;

            // TODO: Appropriate initialization when these things are null.  Otherwise, we just leave what the
            // last loaded theme had.
            if (item.effectLst != null)
                controls.editEffect.EffectList = item.effectLst;

            controls.enable3D.Checked = item.scene3d != null || item.sp3d != null;
            if (item.scene3d != null)
                controls.editScene.Scene3D = item.scene3d;
            if (item.sp3d != null)
                controls.edit3D.Shape3D = item.sp3d;
        }

        private void LoadEffectStyles(OfficeOpenXMLInterop.CT_EffectStyleItem[] effectList)
        {
            if (effectList.Length != 3)
                return; // TODO: throw some kind of error

            for (int i = 0; i < 3; i++ )
                LoadEffectStyle(effectList[i], effectControls[i]);
        }
        #endregion

        #endregion

        #endregion

        #region Theme Colors

        public void InformPlaceholderColorChanged()
        {
            Color newColor;
            switch (this.comboBoxPlaceholderSample.Text)
            {
                case "Accent 1":
                    newColor = panelAccent1.BackColor;
                    break;
                case "Accent 2":
                    newColor = panelAccent2.BackColor;
                    break;
                case "Accent 3":
                    newColor = panelAccent3.BackColor;
                    break;
                case "Accent 4":
                    newColor = panelAccent4.BackColor;
                    break;
                case "Accent 5":
                    newColor = panelAccent5.BackColor;
                    break;
                case "Accent 6":
                    newColor = panelAccent6.BackColor;
                    break;
                default:
                    System.Diagnostics.Debug.Fail("Unexpected value for sample color");
                    return;
            }

            this.gradientEditorSubtleFill.PlaceholderColor = newColor;
            this.editImageSubtleFill.PlaceholderColor = newColor;
            this.gradientEditorModerateFill.PlaceholderColor = newColor;
            this.editImageModerateFill.PlaceholderColor = newColor;
            this.gradientEditorIntenseFill.PlaceholderColor = newColor;
            this.editImageIntenseFill.PlaceholderColor = newColor;
            this.gradientEditorBgSubtleFill.PlaceholderColor = newColor;
            this.editImageBgSubtleFill.PlaceholderColor = newColor;
            this.gradientEditorBgModerateFill.PlaceholderColor = newColor;
            this.editImageBgModerateFill.PlaceholderColor = newColor;
            this.gradientEditorBgIntenseFill.PlaceholderColor = newColor;
            this.editImageBgIntenseFill.PlaceholderColor = newColor;
            this.panelPlaceholderColor.BackColor = newColor;
        }

        private void comboBoxPlaceholderSample_SelectedIndexChanged(object sender, EventArgs e)
        {
            InformPlaceholderColorChanged();
        }

        private void checkBoxUseSystemColors_CheckedChanged(object sender, EventArgs e)
        {
            if (this.checkBoxUseSystemColors.Checked)
            {
                EnableLightDark1(false);

                SetLight1Color(SystemColors.Window);
                SetDark1Color(SystemColors.WindowText);
            }
            else
            {
                EnableLightDark1(true);
            }
        }

        private void EnableLightDark1(bool enable)
        {
            this.panelLight1.Enabled = enable;
            this.panelDark1.Enabled = enable;
        }

        private void light1_Click(object sender, EventArgs e)
        {
            if (this.panelLight1.Enabled)
            {
                this.colorDialog1.Color = this.panelLight1.BackColor;

                if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
                {
                    SetLight1Color( this.colorDialog1.Color );
                }
            }
        }

        private void dark1_Click(object sender, EventArgs e)
        {
            if (this.panelDark1.Enabled)
            {
                this.colorDialog1.Color = this.panelDark1.BackColor;

                if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
                {
                    SetDark1Color(this.colorDialog1.Color);
                }
            }
        }

        private void light2_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelLight2.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                SetLight2Color(this.colorDialog1.Color);
            }
        }

        private void dark2_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelDark2.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                SetDark2Color(this.colorDialog1.Color);
            }
        }

        private void accent1_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelAccent1.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                this.panelAccent1.BackColor = this.colorDialog1.Color;
                this.panelAccent1Show.BackColor = this.colorDialog1.Color;

                this.InformPlaceholderColorChanged();
            }
        }

        private void accent2_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelAccent2.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                this.panelAccent2.BackColor = this.colorDialog1.Color;
                this.panelAccent2Show.BackColor = this.colorDialog1.Color;

                this.InformPlaceholderColorChanged();
            }
        }

        private void accent3_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelAccent3.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                this.panelAccent3.BackColor = this.colorDialog1.Color;
                this.panelAccent3Show.BackColor = this.colorDialog1.Color;

                this.InformPlaceholderColorChanged();
            }
        }

        private void accent4_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelAccent4.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                this.panelAccent4.BackColor = this.colorDialog1.Color;
                this.panelAccent4Show.BackColor = this.colorDialog1.Color;

                this.InformPlaceholderColorChanged();
            }
        }

        private void accent5_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelAccent5.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                this.panelAccent5.BackColor = this.colorDialog1.Color;
                this.panelAccent5Show.BackColor = this.colorDialog1.Color;

                this.InformPlaceholderColorChanged();
            }
        }

        private void accent6_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelAccent6.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                this.panelAccent6.BackColor = this.colorDialog1.Color;
                this.panelAccent6Show.BackColor = this.colorDialog1.Color;

                this.InformPlaceholderColorChanged();
            }
        }

        private void hyperlink_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelHyperlink.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                this.panelHyperlink.BackColor = this.colorDialog1.Color;
                this.labelHyperlinkShow.ForeColor = this.colorDialog1.Color;
            }
        }

        private void followedHyperlink_Click(object sender, EventArgs e)
        {
            this.colorDialog1.Color = this.panelFollowedHyperlink.BackColor;

            if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
            {
                this.panelFollowedHyperlink.BackColor = this.colorDialog1.Color;
                this.labelFollowedHyperlinkShow.ForeColor = this.colorDialog1.Color;
            }
        }

        private void panelAccent1_BackColorChanged(object sender, EventArgs e)
        {
            if (this.panelAccent1.BackColor != Color.White)
            {
                this.labelAccent1.ForeColor = Color.White;
            }
        }

        private void panelAccent2_BackColorChanged(object sender, EventArgs e)
        {
            if (this.panelAccent2.BackColor != Color.White)
            {
                this.labelAccent2.ForeColor = Color.White;
            }
        }

        private void panelAccent3_BackColorChanged(object sender, EventArgs e)
        {
            if (this.panelAccent3.BackColor != Color.White)
            {
                this.labelAccent3.ForeColor = Color.White;
            }
        }

        private void panelAccent4_BackColorChanged(object sender, EventArgs e)
        {
            if (this.panelAccent4.BackColor != Color.White)
            {
                this.labelAccent4.ForeColor = Color.White;
            }
        }

        private void panelAccent5_BackColorChanged(object sender, EventArgs e)
        {
            if (this.panelAccent5.BackColor != Color.White)
            {
                this.labelAccent5.ForeColor = Color.White;
            }
        }

        private void panelAccent6_BackColorChanged(object sender, EventArgs e)
        {
            if (this.panelAccent6.BackColor != Color.White)
            {
                this.labelAccent6.ForeColor = Color.White;
            }
        }

        #endregion

        #region Fill Styles
        private FillStyleControls GetFillStyleControls(object sender)
        {
            foreach (FillStyleControls controls in fillControls)
                if (sender == controls.comboFill)
                    return controls;

            System.Diagnostics.Debug.Assert(false, "Unrecognized control");
            return null;
        }

        private void comboBoxFill_SelectedIndexChanged(object sender, EventArgs e)
        {
            FillStyleControls controls = GetFillStyleControls(sender);
            controls.editColor.Visible = (controls.comboFill.SelectedIndex == 0);
            controls.gradientEditor.Visible = (controls.comboFill.SelectedIndex == 1);
            controls.editImage.Visible = (controls.comboFill.SelectedIndex == 2);
            // TODO: Pattern fill
        }
        #endregion

        #region Effect Styles

        private EffectStyleControls GetEffectStyleControls(object sender)
        {
            foreach (EffectStyleControls controls in effectControls)
                if (sender == controls.enable3D)
                    return controls;

            System.Diagnostics.Debug.Assert(false, "Unrecognized control");
            return null;
        }

        private void checkBoxEnable3D_CheckedChanged(object sender, EventArgs e)
        {
            EffectStyleControls controls = GetEffectStyleControls(sender);
            controls.editScene.Enabled = controls.enable3D.Checked;
            controls.edit3D.Enabled = controls.enable3D.Checked;
        }
        #endregion


        private void light2Label_Click(object sender, EventArgs e)
        {

        }

        private void SetDark1Color(Color color)
        {
            this.labelDark1.BackColor = color;
            this.panelDark1.BackColor = color;

            this.panelDark1Show.BackColor = color;

            this.labelLight1.ForeColor = color;
        }

        private void SetLight1Color(Color color)
        {
            this.panelLight1.BackColor = color;
            this.labelLight1.BackColor = color;

            this.labelLight1Show.ForeColor = color;

            this.labelDark1.ForeColor = color;
        }

        private void SetDark2Color(Color color)
        {
            this.panelDark2.BackColor = color;
            this.labelDark2.BackColor = color;

            this.panelDark2Show.BackColor = color;

            this.labelLight2.ForeColor = color;
        }

        private void SetLight2Color(Color color)
        {
            this.labelLight2.BackColor = color;
            this.panelLight2.BackColor = color;

            this.labelLight2Show.ForeColor = color;

            this.labelDark2.ForeColor = color;
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // TODO
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            About about = new About();
            about.ShowDialog(this);
        }
     
    }
}